<?php

declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use think\Db\Exception\DbException;
use think\facade\Db;

class MakeUpCode extends Command
{
    protected function configure()
    {
        // 指令配置
        $this->setName('make:code')
            ->setDescription('根据表名生成控制器代码')
            ->addArgument('table', Argument::REQUIRED, '表名');
    }

    /**
     * 获取数据库表结构
     * @param string $tableName 表名
     * @return array 字段信息
     * @throws DbException
     */
    private function getTableFields(string $tableName): array
    {
        try {
            // 检查数据库连接
            $dbConfig = config('database.connections.mysql');
            if (empty($dbConfig['database'])) {
                throw new DbException('数据库名未配置，请在 .env 文件中设置 DB_NAME');
            }

            // 检查表是否存在
            $tables = Db::query('SHOW TABLES');
            $tableExists = false;
            $tablePrefix = $dbConfig['prefix'] ?? '';
            $fullTableName = $tablePrefix . $tableName;

            foreach ($tables as $table) {
                $key = 'Tables_in_' . $dbConfig['database'];
                if ($table[$key] === $fullTableName) {
                    $tableExists = true;
                    break;
                }
            }

            if (!$tableExists) {
                throw new DbException('表 ' . $fullTableName . ' 不存在于数据库 ' . $dbConfig['database'] . ' 中');
            }

            // 获取表结构
            $fields = Db::query('DESCRIBE ' . $fullTableName);

            // 过滤不需要的字段
            $filteredFields = [];
            $excludedFields = ['createTime', 'updateTime', 'deleteTime'];

            foreach ($fields as $field) {
                // 排除指定字段
                if (!in_array($field['Field'], $excludedFields)) {
                    $filteredFields[] = $field;
                }
            }

            return $filteredFields;
        } catch (DbException $e) {
            throw new DbException('获取表结构失败: ' . $e->getMessage());
        }
    }

    protected function execute(Input $input, Output $output)
    {
        // 获取表名参数
        $tableName = $input->getArgument('table');

        // 确保表名不为空
        if (empty($tableName)) {
            $output->error('错误: 请提供表名');
            return 1;
        }

        try {
            // 获取表结构字段
            $fields = $this->getTableFields($tableName);
            if (empty($fields)) {
                $output->error('错误: 未找到表 ' . $tableName . ' 的字段信息或所有字段都被排除');
                return 1;
            }
            $output->info('成功获取表 ' . $tableName . ' 的字段信息，共 ' . count($fields) . ' 个字段');
        } catch (DbException $e) {
            $output->error('错误: ' . $e->getMessage());
            return 1;
        }

        // 转换表名为首字母大写的格式（用于类名）
        $className = ucfirst($tableName);
        // 变量名（小写）
        $varName = $tableName;
        // 手动构建路径，确保兼容性
        $appPath = app_path();
        // 确保路径末尾有目录分隔符
        $appPath = rtrim($appPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
        // 模板文件路径
        $templatePath = $appPath . 'admin' . DIRECTORY_SEPARATOR . 'controller' . DIRECTORY_SEPARATOR . 'template.php';
        // 目标文件路径
        $targetPath = $appPath . 'admin' . DIRECTORY_SEPARATOR . 'controller' . DIRECTORY_SEPARATOR . $className . '.php';

        // 生成查询条件代码
        $queryConditions = '';
        foreach ($fields as $field) {
            $fieldName = $field['Field'];
            if ($fieldName == 'id') {
                continue;
            }
            // id 字段已经有特殊处理
            // 根据字段类型生成不同的查询条件
            if (stripos($field['Type'], 'varchar') !== false || stripos($field['Type'], 'text') !== false) {
                $queryConditions .= "            } else if (\$key == '$fieldName') {
                \$where[] = ['$fieldName', 'like', \"%{\$value}%\"];
";
            } else {
                $queryConditions .= "            } else if (\$key == '$fieldName') {
                \$where[] = ['$fieldName', '=', \$value];
";
            }
        }

        // 调试信息
        $output->writeln('模板文件路径: ' . $templatePath);
        $output->writeln('目标文件路径: ' . $targetPath);

        try {
            // 读取模板文件内容
            if (!file_exists($templatePath)) {
                throw new \Exception('模板文件不存在: ' . $templatePath);
            }

            $templateContent = file_get_contents($templatePath);

            // 替换模板中的查询条件
            $newQueryCode = '$query = $this->request->param();
        $where = [];
        foreach ($query as $key => $value) {
            if ($key == \'id\') {
                continue;
            ' . $queryConditions . '}}';
            $templateContent = str_replace(
                '// 查询条件',
                $newQueryCode,
                $templateContent
            );

            // 生成验证规则代码
            $validateRulesAdd = '';
            $validateRulesEdit = '';
            $primaryKey = '';

            foreach ($fields as $field) {
                $fieldName = $field['Field'];
                // 检查是否为主键
                if ($field['Key'] == 'PRI') {
                    $primaryKey = $fieldName;
                }

                $rule = '';
                // 必填字段
                if ($field['Null'] == 'NO' && empty($field['Default']) && $field['Extra'] != 'auto_increment') {
                    $rule .= 'require|';
                }
                // 字符串长度限制
                if (stripos($field['Type'], 'varchar') !== false) {
                    preg_match('/varchar\((\d+)\)/i', $field['Type'], $matches);
                    if (!empty($matches[1])) {
                        $rule .= 'max:' . $matches[1] . '|';
                    }
                }
                // 移除末尾的分隔符
                $rule = rtrim($rule, '|');

                if (!empty($rule)) {
                    if (!empty($validateRulesAdd)) {
                        $validateRulesAdd .= ',';
                    }
                    $validateRulesAdd .= '            \'' . $fieldName . '\' => \'' . $rule . '\'';
                }
            }

            // 编辑方法的验证规则（添加主键验证）
            $validateRulesEdit = '            \'' . $primaryKey . '\' => \'require\'';
            if (!empty($validateRulesAdd)) {
                $validateRulesEdit .= ',' . $validateRulesAdd;
            }

            // 替换模板中的内容
            // 替换类名
            $templateContent = str_replace('class Template extends BaseController', 'class ' . $className . ' extends BaseController', $templateContent);
            // 替换数据库表名引用
            $templateContent = str_replace("Db::name('template')", "Db::name('$tableName')", $templateContent);

            // 替换add方法的验证规则
            $addValidateCode = <<<EOD
                            \$this->validate(\$data, [$validateRulesAdd]);
                            EOD;
            $templateContent = str_replace(
                '// 校验新增参数',
                $addValidateCode,
                $templateContent
            );

            // 替换edit方法的验证规则
            $editValidateCode = <<<EOD
        \$this->validate(\$data, [$validateRulesEdit]);
EOD;
            $templateContent = str_replace(
                '// 校验编辑参数',
                $editValidateCode,
                $templateContent
            );

            // 替换其他模板名称引用
            $templateContent = str_replace("'template'", "'$tableName'", $templateContent);
            // 替换中文提示中的模板名称
            $templateContent = str_replace('模板不存在', $tableName . '不存在', $templateContent);
            $templateContent = str_replace('获取成功', '获取' . $tableName . '成功', $templateContent);
            $templateContent = str_replace('新增失败', '新增' . $tableName . '失败', $templateContent);
            $templateContent = str_replace('新增成功', '新增' . $tableName . '成功', $templateContent);
            $templateContent = str_replace('编辑成功', '编辑' . $tableName . '成功', $templateContent);
            // 替换变量名 $template
            $templateContent = str_replace('$template', '$' . $tableName, $templateContent);

            // 写入新文件
            $result = file_put_contents($targetPath, $templateContent);
            if ($result === false) {
                throw new \Exception('写入文件失败: ' . $targetPath);
            }

            $output->info('成功生成文件: ' . $targetPath);

            // 生成vue文件
            try {
                // 读取vue模板文件
                $vueTemplatePath = root_path() . 'view' . DIRECTORY_SEPARATOR . 'index.vue';
                if (!file_exists($vueTemplatePath)) {
                    throw new \Exception('Vue模板文件不存在: ' . $vueTemplatePath);
                }

                $vueContent = file_get_contents($vueTemplatePath);

                // 替换模板中的内容
                $vueContent = str_replace('template', strtolower($className), $vueContent);
                $vueContent = str_replace('Template', $className, $vueContent);
                $vueContent = str_replace('用户管理', $className . '管理', $vueContent);
                $vueContent = str_replace('admin/template', 'admin/' . strtolower($className), $vueContent);

                // 生成目标文件路径
                $vueTargetPath = $appPath . 'command' . DIRECTORY_SEPARATOR . $className . '.vue';

                // 写入新文件
                $vueResult = file_put_contents($vueTargetPath, $vueContent);
                if ($vueResult === false) {
                    throw new \Exception('写入Vue文件失败: ' . $vueTargetPath);
                }

                $output->info('成功生成Vue文件: ' . $vueTargetPath);
            } catch (\Exception $e) {
                $output->error('生成Vue文件失败: ' . $e->getMessage());
            }

            // 生成文件成功后将路由添加到数据库
            $route = [
                [
                    'name' => $tableName . '详情',
                    'path' => "/" . "admin/" . strtolower($tableName) . '/index',
                    "status" => 1,
                ],
                [
                    'name' => $tableName . '列表',
                    'path' => "/" . "admin/" . strtolower($tableName) . '/list',
                    "status" => 1,

                ],
                [
                    'name' => $tableName . '新增',
                    'path' => "/" . "admin/" . strtolower($tableName) . '/add',
                    "status" => 1,

                ],
                [
                    'name' => $tableName . '编辑',
                    'path' => "/" . "admin/" . strtolower($tableName) . '/edit',
                    "status" => 1,

                ],
                [
                    'name' => $tableName . '删除',
                    'path' => "/" . "admin/" . strtolower($tableName) . '/remove',
                    "status" => 1,

                ],
                [
                    'name' => $tableName . '恢复',
                    'path' => "/" . "admin/" . strtolower($tableName) . '/recover',
                    "status" => 1,

                ],
            ];
            Db::name('permission')->insertAll($route);

            return 0;
        } catch (\Exception $e) {
            $output->error('生成文件失败: ' . $e->getMessage());
            return 1;
        }
    }
}
